﻿using MudBlazor.Utilities;

namespace MXERP.Blazor.Components
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public partial class ComboBoxItem<T> : MudBaseSelectItem, IDisposable
    {
        /// <summary>
        /// 
        /// </summary>
        protected string? Classname => new CssBuilder("md-combobox-item")
            .AddClass($"md-combobox-item-{ComboBox?.Dense.ToDescriptionString()}")
            .AddClass("md-ripple", Ripple && !Disabled)
            .AddClass("md-combobox-item-gutters")
            .AddClass("md-combobox-item-clickable")
            .AddClass("md-combobox-item-hilight", Active && !Disabled)
            .AddClass("md-combobox-item-hilight-selected", Active && Selected && !Disabled)
            .AddClass($"md-selected-item mud-{ComboBox?.Color.ToDescriptionString()}-text mud-{ComboBox?.Color.ToDescriptionString()}-hover", Selected && !Disabled && !Active)
            .AddClass("md-combobox-item-disabled", Disabled)
            .AddClass("md-combobox-item-bordered", ComboBox?.Bordered == true && Active)
            .AddClass($"md-combobox-item-bordered-{ComboBox?.Color.ToDescriptionString()}", ComboBox?.Bordered == true && Selected)
            .AddClass("d-none", !Eligible)
            .AddClass(Class)
            .Build();

        /// <summary>
        /// 
        /// </summary>
        protected string? HighlighterClassname => ComboBox is null ? null : new CssBuilder()
            .AddClass("md-combobox-highlighter", ComboBox.Highlight && string.IsNullOrWhiteSpace(ComboBox.HighlightClass))
            .AddClass(ComboBox?.HighlightClass, ComboBox?.Highlight)
            .Build();

        internal string ItemId { get; } = string.Concat("_", Guid.NewGuid().ToString().AsSpan(0, 8));

        /// <summary>
        /// The parent select component
        /// </summary>
        [CascadingParameter]
        ComboBox<T> ComboBox { get; set; }

        /// <summary>
        /// The text to display
        /// </summary>
        [Parameter]
        [Category(CategoryTypes.List.Behavior)]
        public string? Text { get; set; }

        /// <summary>
        /// A user-defined option that can be selected
        /// </summary>
        [Parameter]
        [Category(CategoryTypes.FormComponent.Behavior)]
        public T? Value { get; set; }

        /// <summary>
        /// The color of the text. It supports the theme colors.
        /// </summary>
        [Parameter]
        [Category(CategoryTypes.List.Behavior)]
        public Color? TextColor { get; set; } = null;

        /// <summary>
        /// The color of the checked checkbox. It supports the theme colors.
        /// </summary>
        [Parameter]
        [Category(CategoryTypes.List.Behavior)]
        public Color? CheckBoxCheckedColor { get; set; } = null;

        /// <summary>
        /// The color of the unchecked checkbox. It supports the theme colors.
        /// </summary>
        [Parameter]
        [Category(CategoryTypes.Radio.Appearance)]
        public Color? CheckBoxUnCheckedColor { get; set; } = null;

        /// <summary>
        /// The size of the checkbox.
        /// </summary>
        [Parameter]
        [Category(CategoryTypes.FormComponent.Appearance)]
        public Size? CheckBoxSize { get; set; } = null;

        /// <summary>
        /// 
        /// </summary>
        protected internal bool Selected { get; set; }
        /// <summary>
        /// 
        /// </summary>
        protected internal bool Active { get; set; }

        /// <summary>
        /// Change the item's active status.
        /// </summary>
        /// <param name="isActive"></param>
        public void SetActive(bool isActive)
        {
            Active = isActive;
            //StateHasChanged();
        }

        /// <summary>
        /// 
        /// </summary>
        [Parameter]
        public bool Eligible { get; set; } = true;

        /// <summary>
        /// 
        /// </summary>
        protected string? DisplayString
        {
            get
            {
                var converter = ComboBox?.Converter;
                if (ComboBox?.ItemPresenter == ValuePresenter.None)
                {
                    if (converter == null)
                        return Value?.ToString();
                    return converter.Set(Value);
                }

                if (converter == null)
                    return $"{(string.IsNullOrWhiteSpace(Text) ? Value : Text)}";
                return !string.IsNullOrWhiteSpace(Text) ? Text : converter.Set(Value);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void ForceRender()
        {
            CheckEligible();
            StateHasChanged();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public async Task ForceUpdate()
        {
            SyncSelected();
            await InvokeAsync(StateHasChanged);
        }

        /// <summary>
        /// 
        /// </summary>
        protected override void OnInitialized()
        {
            ComboBox?.AddItem(this);
        }

        //bool? _oldMultiselection;
        //bool? _oldSelected;
        bool _selectedChanged = false;
        //bool? _oldEligible = true;
        //bool _eligibleChanged = false;
        /// <summary>
        /// 
        /// </summary>
        protected override void OnParametersSet()
        {
            base.OnParametersSet();
            //SyncSelected();
            //if (_oldSelected != Selected || _oldEligible != Eligible)
            //{
            //    _selectedChanged = true;
            //}
            //_oldSelected = Selected;
            CheckEligible();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="firstRender"></param>
        /// <returns></returns>
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            await base.OnAfterRenderAsync(firstRender);
            if (_selectedChanged)
            {
                _selectedChanged = false;
                await InvokeAsync(StateHasChanged);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        protected internal void CheckEligible()
        {
            Eligible = IsEligible();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected bool IsEligible()
        {
            if (ComboBox is null)
                return true;

            if (!ComboBox.Editable || ComboBox.EnableFilter == false)
                return true;

            if (string.IsNullOrWhiteSpace(ComboBox._searchString))
                return true;

            if (ComboBox.SearchFunc is not null)
                return ComboBox.SearchFunc.Invoke(Value, Text, ComboBox.GetSearchString());

            if (!string.IsNullOrWhiteSpace(Text))
            {
                if (Text.Contains(ComboBox._searchString ?? string.Empty, StringComparison.OrdinalIgnoreCase))
                    return true;
            }
            else
            {
                if (ComboBox?.Converter?.Set(Value)?.Contains(ComboBox._searchString ?? string.Empty, StringComparison.OrdinalIgnoreCase) == true)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        protected void SyncSelected()
        {
            if (ComboBox is null)
                return;

            if (ComboBox.MultiSelection && ComboBox?.SelectedValues?.Contains(Value) == true)
                Selected = true;

            else if (ComboBox?.MultiSelection == false && ((ComboBox.Value is null && Value is null) || ComboBox.Value?.Equals(Value) == true))
                Selected = true;
            else
                Selected = false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected async Task HandleOnClick()
        {
            await ComboBox.ToggleOption(this, !Selected);
            await InvokeAsync(StateHasChanged);
            await ComboBox.FocusAsync();
            await OnClick.InvokeAsync();
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            try
            {
                ComboBox?.RemoveItem(this);
            }
            catch { }
        }
    }
}
